
#include "uci_adults.h"

int main(int argc, const char* argv[])
{
	int nRetCode = 0;
	CMyRandom::InitRandomSeed();
	CImageEx::Initialize();

	if (1)
	{
		string strFN_Configuration		=	argv[1];
		string strOperation				=	argv[2];

		strOperation += "00000000";

		//int op_SVM_FirstRound = CDataStructureTools::Hex2Num(strOperation[0]);

		char strTemp[10001] = "";

		//////////	Config Loading	//////////

		CConfiguration Config(strFN_Configuration);
		Config.Load();

		string strFN_OutLog =
			Config.GetString("strFN_OutLog", "Global.log");
		string strFN_ShortLog =
			Config.GetString("strFN_ShortLog", "Short.log");

		sprintf_s(strTemp, "del %s", strFN_OutLog.c_str());
		CExternalTools::ConsoleTools::RunDosCommand("", strTemp);
		sprintf_s(strTemp, "del %s", strFN_ShortLog.c_str());
		CExternalTools::ConsoleTools::RunDosCommand("", strTemp);

		ofstream outLog(strFN_OutLog.c_str());
		CExternalTools::ConsoleTools::MakeCurrentLine("", true);
		CExternalTools::ConsoleTools::OutputTextToStream(outLog, "", true);
		ofstream outFile_ShortLog(strFN_ShortLog.c_str());

		EnvVar.strFN_AttributeSetSettings =
			Config.GetString("strFN_AttributeSetSettings");
		EnvVar.strFN_Data_Train =
			Config.GetString("strFN_Data_Train");
		EnvVar.strFN_Data_Test =
			Config.GetString("strFN_Data_Test");

		CAttributeSetSettings& ASS = EnvVar.ASS;
		ASS.LoadConfigFromFile(EnvVar.strFN_AttributeSetSettings);

		sprintf_s(strTemp, "Loaded Attribute Set Settings; |Attribute| = [%d]; |Feature| = [%d];",
			ASS.AttributeAmount, ASS.FeatureDimension);
		CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
		CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
		CExternalTools::ConsoleTools::MakeCurrentLine("", true);
		CExternalTools::ConsoleTools::OutputTextToStream(outLog, "", true);

		datasets_uci::C_UCI_LabeledDataSet SourceDataSet_Train;
		SourceDataSet_Train.InitAttributeSetSettings(&ASS);
		SourceDataSet_Train.InitData(EnvVar.strFN_Data_Train);

		sprintf_s(strTemp, "Loaded Source Data [Train]; |Example| = [%d];",
			SourceDataSet_Train.GetExampleAmount());
		CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
		CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
		CExternalTools::ConsoleTools::MakeCurrentLine("", true);
		CExternalTools::ConsoleTools::OutputTextToStream(outLog, "", true);

		datasets_uci::C_UCI_LabeledDataSet SourceDataSet_Test;
		SourceDataSet_Test.InitAttributeSetSettings(&ASS);
		SourceDataSet_Test.InitData(EnvVar.strFN_Data_Test);

		sprintf_s(strTemp, "Loaded Source Data [Test]; |Example| = [%d];",
			SourceDataSet_Test.GetExampleAmount());
		CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
		CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
		CExternalTools::ConsoleTools::MakeCurrentLine("", true);
		CExternalTools::ConsoleTools::OutputTextToStream(outLog, "", true);

		// ********** Main Code Start **********
		if (1)
		{
			CDataSetForBinaryClassification bds_Train;
			bds_Train.SetRealDataSet(&SourceDataSet_Train);
			bds_Train.SetTargetLabel(1);

			CDataSetForBinaryClassification bds_Test;
			bds_Test.SetRealDataSet(&SourceDataSet_Test);
			bds_Test.SetTargetLabel(1);

			CBinaryClassificationExampleList BEL_Full_Train;
			BEL_Full_Train.myInit(&bds_Train);

			CBinaryClassificationExampleList BEL_Full_Test;
			BEL_Full_Test.myInit(&bds_Test);

			CAdaBoostParameterConfig AdaBoostParameters;
			AdaBoostParameters.SFC_BinAmount = 100;
			AdaBoostParameters.SFC_FeatureSampleRate = 1.0;
			AdaBoostParameters.fOutputTrainLogToScreen = false;
			AdaBoostParameters.fOutputTrainLogToLogStream = false;

			CAdaBoostTrainingEndCondition AdaBoostTrainingEndCondition(60);

			//CAdaBoostClassifier AdaBoostClassifier;
			//AdaBoostClassifier.Train(
			//	&bds_Train, BEL_Full_Train,
			//	&bds_Test, BEL_Full_Test,
			//	AdaBoostParameters, 60, outLog);

			if (1)
			{
				double ForDifficultyClassificationRatio = 0.01;
				double HardExampleRatio = 0.50;
				int RepeatAmount = 400;

				//int SampleRateRoundAmount = 15;
				//double SampleRateBase = 0.01;
				//double SampleRateIncreaseStep = 0.01;
				int SampleRateRoundAmount = 8;
				double sr_b = 0.002;
				double sr_s = 2.4;

				int i_difficulty, i_sample_round, i_repeat;
				int i_example;
				CAdaBoostTrainingResultForPosNegExampleList TR_1;
				CAdaBoostTrainingResultForPosNegExampleList TR_2;
				CAdaBoostClassifier AdaBoostClassifier;

				CWeightedClassificationExampleList EL_Full_Train;
				EL_Full_Train.myInit(&SourceDataSet_Train);
				CWeightedClassificationExampleList EL_Full_Test;
				EL_Full_Test.myInit(&SourceDataSet_Test);

				sprintf_s(strTemp, "Preselecting Sample Rate [%.3lf];", ForDifficultyClassificationRatio);
				CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
				CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);

				double osa, osv, opm;
				osa = osv = 0.0;
				for ( i_difficulty = 0; i_difficulty < 2; ++i_difficulty )
				{
					for ( i_sample_round = 0; i_sample_round < SampleRateRoundAmount; ++i_sample_round )
					{
						//double sr = SampleRateBase + SampleRateIncreaseStep * i_sample_round;
						double sr = sr_b * pow(sr_s, i_sample_round);

						double sa, sb, sv, pm, pv;
						sa = sb = sv = 0.0;
						for ( i_repeat = 0; i_repeat < RepeatAmount; ++i_repeat )
						{
							CWeightedClassificationExample tExample;
							CWeightedClassificationExampleList tList;
							CBinaryClassificationExampleList tBinaryList;

							CWeightedClassificationExampleList EL_Small;
							CWeightedClassificationExampleList EL_Big;
							CBinaryClassificationExampleList BEL_Small;
							CBinaryClassificationExampleList BEL_Big;
							EL_Small.Clear();
							EL_Big.Clear();
							for ( i_example = 0; i_example < EL_Full_Train.ExampleAmount; ++i_example )
							{
								bool fToSmall = (CMyRandom::NextDouble() < ForDifficultyClassificationRatio);
								(fToSmall ? EL_Small : EL_Big).PushBack(EL_Full_Train.rgExample[i_example]);
							}
							BEL_Small.myInit(&bds_Train, EL_Small);
							BEL_Big.myInit(&bds_Train, EL_Big);

							BEL_Small.BalanceRelativePosNegTotalWeightRatio(
								BEL_Full_Train.PosList.TotalExampleWeight / BEL_Full_Train.NegList.TotalExampleWeight);
							AdaBoostClassifier.Train(
								&bds_Train, BEL_Small,
								&bds_Train, BEL_Big,
								AdaBoostParameters, AdaBoostTrainingEndCondition,
								TR_1, TR_2, outLog);

							int tp;
							double tc;
							CBinaryClassificationResult_ByPrediction obr;
							obr.Clear();
							for ( i_example = 0; i_example < EL_Full_Test.ExampleAmount; ++i_example )
							{
								tExample = EL_Full_Test.rgExample[i_example];
								AdaBoostClassifier.Classify(&SourceDataSet_Test, tExample.ExampleIndex, tc, tp);
								if (bds_Test.IsExamplePos(tExample.ExampleIndex))
									obr.NewTest(+1, tp, tExample.Weight);
								else
									obr.NewTest(-1, tp, tExample.Weight);
							}
							obr.Analyse();
							osa += 100.0 - 100.0 * obr.wErrorRate; osv += 1.0; opm = osa / osv;

							CBinaryClassificationExampleList EasyList_Full;
							CBinaryClassificationExampleList HardList_Full;
							TR_2.MakeList(tBinaryList);
							tList.Clear();
							for ( i_example = 0; i_example < tBinaryList.PosList.ExampleAmount; ++i_example )
							{
								tExample = tBinaryList.PosList.rgExample[i_example];
								tExample.Weight = 0.0 + tExample.Weight;
								tList.PushBack(tExample);
							}
							for ( i_example = 0; i_example < tBinaryList.NegList.ExampleAmount; ++i_example )
							{
								tExample = tBinaryList.NegList.rgExample[i_example];
								tExample.Weight = 0.0 - tExample.Weight;
								tList.PushBack(tExample);
							}
							tList.ComputeTotalExampleWeight();
							tList.SortByWeight();
							tBinaryList.Clear();
							for ( i_example = 0; i_example < tList.ExampleAmount; ++i_example )
							{
								bool fIsEasy = (tList.ExampleAmount*HardExampleRatio > i_example+0.5);
								tExample = tList.rgExample[i_example];
								(fIsEasy ? tBinaryList.PosList : tBinaryList.NegList).PushBack(tExample.ExampleIndex, 1.0);
							}
							tBinaryList.ComputeTotalExampleWeight();
							tBinaryList.SortByIndex();
							EasyList_Full.myInit(&bds_Train, tBinaryList.PosList);
							HardList_Full.myInit(&bds_Train, tBinaryList.NegList);
							sprintf_s(strTemp, "Mode [%s] SR [%.3lf] Rp [%d/%d]: S/EP/EN/HP/HN [%d/%d/%d/%d/%d]",
								(i_difficulty==0 ? "Easy" : "Hard"), sr, i_repeat+1, RepeatAmount,
								EL_Small.ExampleAmount,
								EasyList_Full.PosList.ExampleAmount, EasyList_Full.NegList.ExampleAmount,
								HardList_Full.PosList.ExampleAmount, HardList_Full.NegList.ExampleAmount);
							//CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
							//CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);

							if (i_difficulty == 0)
								tBinaryList.myInit(EasyList_Full, sr);
							else
								tBinaryList.myInit(HardList_Full, sr);

							tBinaryList.BalanceRelativePosNegTotalWeightRatio(
								BEL_Full_Train.PosList.TotalExampleWeight / BEL_Full_Train.NegList.TotalExampleWeight);
							AdaBoostClassifier.Train(
								&bds_Train, tBinaryList,
								&bds_Test, BEL_Full_Test,
								AdaBoostParameters, AdaBoostTrainingEndCondition,
								TR_1, TR_2, outLog);

							double acc100 = 100.0 - 100.0 * TR_2.ClassificationResult_ByPrediction.wErrorRate;

							sa += acc100; sb += acc100 * acc100; sv += 1.0;
							pm = sa / sv; pv = sb / sv - pm * pm; pv = (pv>0 ? sqrt(pv) : 0);
							sprintf_s(strTemp, "Mode [%s] SR [%.3lf] Rp [%d/%d]: Acc%% [%.2lf | %.2lf] oAcc%% [%.2lf];",
								(i_difficulty==0 ? "Easy" : "Hard"), sr, i_repeat+1, RepeatAmount, pm, pv, opm);
							CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, false);
						} // i_repeat

						sprintf_s(strTemp, "%s\t%.3lf\t%.2lf\t%.2lf",
							(i_difficulty==0 ? "Easy" : "Hard"), sr, pm, pv);
						CExternalTools::ConsoleTools::OutputTextToStream(outFile_ShortLog, strTemp, true);
						sprintf_s(strTemp, "Mode [%s] SR [%.3lf]: Acc%% [%.2lf | %.2lf] oAcc%% [%.2lf];",
							(i_difficulty==0 ? "Easy" : "Hard"), sr, pm, pv, opm);
						CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
						CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
					} // i_sample_round
				} // i_difficulty

				sprintf_s(strTemp, "Pre-model Average Acc% [%.2lf];", opm);
				CExternalTools::ConsoleTools::MakeCurrentLine(strTemp, true);
				CExternalTools::ConsoleTools::OutputTextToStream(outLog, strTemp, true);
			}
		} // Main Code

		outFile_ShortLog.close();
		outFile_ShortLog.clear();
		CExternalTools::ConsoleTools::MakeCurrentLine("", true);
		CExternalTools::ConsoleTools::OutputTextToStream(outLog, "", true);
		outLog.close();
		outLog.clear();
	}

	CImageEx::Release();
	return 0;
}

